/**
 * SQLite 持久化购物车示例
 * 
 * 本示例展示如何使用 Proto.Actor 的持久化功能实现一个简单的购物车系统
 * 使用 SQLite 作为持久化存储
 */
import { Actor, ActorSystem, Props, Context, PID } from '../src';
import { 
  PersistentActor, 
  EventType, 
  RecoverContext, 
  CommandContext,
  PersistenceFactory,
  RecoveryStrategy
} from '../src/persistence';

/**
 * 购物车命令类型
 */
enum CartCommandType {
  AddItem = 'add-item',
  RemoveItem = 'remove-item',
  ClearCart = 'clear-cart',
  GetCart = 'get-cart',
  Checkout = 'checkout',
  CreateSnapshot = 'create-snapshot'
}

/**
 * 购物车事件类型
 */
enum CartEventType {
  ItemAdded = 'item-added',
  ItemRemoved = 'item-removed',
  CartCleared = 'cart-cleared',
  CheckedOut = 'checked-out'
}

/**
 * 购物车商品项
 */
interface CartItem {
  productId: string;
  name: string;
  price: number;
  quantity: number;
}

/**
 * 购物车命令
 */
interface CartCommand {
  type: CartCommandType;
  item?: CartItem;
  productId?: string;
}

/**
 * 购物车事件
 */
interface CartEvent {
  type: CartEventType;
  item?: CartItem;
  productId?: string;
  timestamp: number;
}

/**
 * 购物车状态
 */
interface CartState {
  userId: string;
  items: CartItem[];
  checkedOut: boolean;
  lastUpdated: number;
}

/**
 * 持久化购物车 Actor
 */
class ShoppingCartActor extends PersistentActor {
  // 持久化 ID
  private _persistenceId: string;
  
  // 购物车状态
  private state: CartState;
  
  // 事件索引
  private eventIndex: number = 0;
  
  // 上次快照索引
  private lastSnapshotIndex: number = 0;
  
  // 快照间隔 (每处理10个事件创建一次快照)
  private readonly snapshotInterval: number = 10;
  
  /**
   * 构造函数
   * @param userId 用户ID
   */
  constructor(userId: string) {
    super();
    this._persistenceId = `cart-${userId}`;
    
    // 初始化状态
    this.state = {
      userId,
      items: [],
      checkedOut: false,
      lastUpdated: Date.now()
    };
  }
  
  /**
   * 获取持久化 ID
   */
  get persistenceId(): string {
    return this._persistenceId;
  }
  
  /**
   * 恢复事件处理
   * @param context 恢复上下文
   */
  receiveRecover(context: RecoverContext): void {
    const event = context.event;
    
    if (context.eventType === EventType.Snapshot) {
      // 从快照恢复状态
      console.log(`[${this.persistenceId}] Recovering from snapshot:`, event);
      this.state = event as CartState;
      this.lastSnapshotIndex = context.eventIndex;
    } else {
      // 从事件恢复状态
      const cartEvent = event as CartEvent;
      console.log(`[${this.persistenceId}] Recovering from event:`, cartEvent);
      
      this.applyEvent(cartEvent);
      this.eventIndex = context.eventIndex;
    }
  }
  
  /**
   * 命令处理
   * @param context 命令上下文
   */
  receiveCommand(context: CommandContext): void {
    // 如果购物车已结账，大多数操作应该被拒绝
    const message = context.message() as CartCommand;
    
    if (this.state.checkedOut && 
        message.type !== CartCommandType.GetCart && 
        message.type !== CartCommandType.CreateSnapshot) {
      context.respond({ 
        error: true, 
        message: "购物车已结账，无法修改" 
      });
      return;
    }
    
    switch (message.type) {
      case CartCommandType.AddItem:
        this.handleAddItem(context, message);
        break;
        
      case CartCommandType.RemoveItem:
        this.handleRemoveItem(context, message);
        break;
        
      case CartCommandType.ClearCart:
        this.handleClearCart(context);
        break;
        
      case CartCommandType.GetCart:
        // 只读操作，直接返回当前状态
        context.respond({ 
          userId: this.state.userId,
          items: this.state.items,
          checkedOut: this.state.checkedOut,
          total: this.calculateTotal()
        });
        break;
        
      case CartCommandType.Checkout:
        this.handleCheckout(context);
        break;
        
      case CartCommandType.CreateSnapshot:
        this.takeSnapshot(context);
        context.respond({ 
          message: "已创建购物车快照",
          cart: {
            userId: this.state.userId,
            itemCount: this.state.items.length,
            total: this.calculateTotal(),
            checkedOut: this.state.checkedOut
          }
        });
        break;
        
      default:
        console.warn(`[${this.persistenceId}] Unknown command:`, message);
        context.respond({ error: true, message: "未知命令" });
        break;
    }
  }
  
  /**
   * 处理添加商品命令
   */
  private handleAddItem(context: CommandContext, command: CartCommand): void {
    if (!command.item) {
      context.respond({ error: true, message: "商品信息不完整" });
      return;
    }
    
    const item = command.item;
    const event: CartEvent = { 
      type: CartEventType.ItemAdded, 
      item,
      timestamp: Date.now()
    };
    
    this.persist(event).then(() => {
      this.eventIndex++;
      this.applyEvent(event);
      
      context.respond({ 
        success: true, 
        message: `已添加商品: ${item.name}`,
        cart: {
          userId: this.state.userId,
          items: this.state.items,
          total: this.calculateTotal()
        }
      });
      
      this.checkSnapshot(context);
    }).catch(error => {
      context.respond({ error: true, message: `添加商品失败: ${error.message}` });
    });
  }
  
  /**
   * 处理移除商品命令
   */
  private handleRemoveItem(context: CommandContext, command: CartCommand): void {
    if (!command.productId) {
      context.respond({ error: true, message: "未指定要移除的商品ID" });
      return;
    }
    
    const productId = command.productId;
    const itemIndex = this.state.items.findIndex(item => item.productId === productId);
    
    if (itemIndex === -1) {
      context.respond({ error: true, message: `购物车中不存在商品ID: ${productId}` });
      return;
    }
    
    const event: CartEvent = { 
      type: CartEventType.ItemRemoved, 
      productId,
      timestamp: Date.now()
    };
    
    this.persist(event).then(() => {
      this.eventIndex++;
      this.applyEvent(event);
      
      context.respond({ 
        success: true, 
        message: `已移除商品ID: ${productId}`,
        cart: {
          userId: this.state.userId,
          items: this.state.items,
          total: this.calculateTotal()
        }
      });
      
      this.checkSnapshot(context);
    }).catch(error => {
      context.respond({ error: true, message: `移除商品失败: ${error.message}` });
    });
  }
  
  /**
   * 处理清空购物车命令
   */
  private handleClearCart(context: CommandContext): void {
    const event: CartEvent = { 
      type: CartEventType.CartCleared,
      timestamp: Date.now()
    };
    
    this.persist(event).then(() => {
      this.eventIndex++;
      this.applyEvent(event);
      
      context.respond({ 
        success: true, 
        message: "购物车已清空"
      });
      
      // 清空购物车后创建快照
      this.takeSnapshot(context);
    }).catch(error => {
      context.respond({ error: true, message: `清空购物车失败: ${error.message}` });
    });
  }
  
  /**
   * 处理结账命令
   */
  private handleCheckout(context: CommandContext): void {
    if (this.state.items.length === 0) {
      context.respond({ error: true, message: "购物车为空，无法结账" });
      return;
    }
    
    const event: CartEvent = { 
      type: CartEventType.CheckedOut,
      timestamp: Date.now()
    };
    
    this.persist(event).then(() => {
      this.eventIndex++;
      this.applyEvent(event);
      
      const total = this.calculateTotal();
      
      context.respond({ 
        success: true, 
        message: "结账成功",
        checkout: {
          userId: this.state.userId,
          items: this.state.items,
          total,
          timestamp: this.state.lastUpdated
        }
      });
      
      // 结账后创建快照
      this.takeSnapshot(context);
    }).catch(error => {
      context.respond({ error: true, message: `结账失败: ${error.message}` });
    });
  }
  
  /**
   * 应用事件到状态
   * @param event 事件
   */
  private applyEvent(event: CartEvent): void {
    switch (event.type) {
      case CartEventType.ItemAdded:
        if (!event.item) return;
        
        const existingItemIndex = this.state.items.findIndex(
          item => item.productId === event.item!.productId
        );
        
        if (existingItemIndex >= 0) {
          // 更新已有商品的数量
          this.state.items[existingItemIndex].quantity += event.item.quantity;
        } else {
          // 添加新商品
          this.state.items.push({ ...event.item });
        }
        break;
        
      case CartEventType.ItemRemoved:
        if (!event.productId) return;
        
        this.state.items = this.state.items.filter(
          item => item.productId !== event.productId
        );
        break;
        
      case CartEventType.CartCleared:
        this.state.items = [];
        break;
        
      case CartEventType.CheckedOut:
        this.state.checkedOut = true;
        break;
    }
    
    // 更新最后修改时间
    this.state.lastUpdated = event.timestamp;
  }
  
  /**
   * 计算购物车总金额
   */
  private calculateTotal(): number {
    return this.state.items.reduce(
      (total, item) => total + (item.price * item.quantity), 
      0
    );
  }
  
  /**
   * 检查是否需要创建快照
   * @param context 命令上下文
   */
  private checkSnapshot(context: CommandContext): void {
    if (this.eventIndex - this.lastSnapshotIndex >= this.snapshotInterval) {
      this.takeSnapshot(context);
    }
  }
  
  /**
   * 创建状态快照
   * @param context 命令上下文
   */
  private takeSnapshot(context: CommandContext): void {
    this.createSnapshot(this.state).then(() => {
      console.log(`[${this.persistenceId}] Created snapshot:`, {
        userId: this.state.userId,
        itemCount: this.state.items.length,
        checkedOut: this.state.checkedOut
      });
      this.lastSnapshotIndex = this.eventIndex;
    }).catch(error => {
      console.error(`[${this.persistenceId}] Failed to create snapshot:`, error);
    });
  }
  
  /**
   * 恢复完成处理
   * @param context 上下文
   */
  protected onRecoveryCompleted(context: any): void {
    console.log(`[${this.persistenceId}] Recovery completed, cart has ${this.state.items.length} items, ${this.state.checkedOut ? 'is checked out' : 'is active'}`);
  }
}

/**
 * 运行 SQLite 持久化购物车示例
 */
async function runSQLiteShoppingCartExample() {
  console.log('==================================================');
  console.log('| SQLite 持久化购物车示例                        |');
  console.log('==================================================');
  
  // 创建 Actor 系统
  const system = new ActorSystem();
  
  // 获取持久化工厂
  const factory = PersistenceFactory.getInstance();
  
  // 创建 SQLite 持久化提供者
  // 数据将保存在 ./data/cart.db 文件中
  const dbPath = './data/cart.db';
  const provider = factory.createSQLiteProvider(dbPath, 'cart-sqlite');
  
  console.log(`SQLite 数据库路径: ${dbPath}`);
  
  // 创建持久化 Actor 的 Props
  const userId = 'user-123';
  const props = factory.persistentProps(
    () => new ShoppingCartActor(userId),
    'cart-sqlite',
    {
      recoveryStrategy: RecoveryStrategy.SnapshotThenEvents,
      snapshotInterval: 10
    }
  );
  
  // 创建 Actor
  const pid = system.root.spawn(props);
  
  try {
    console.log(`初始化用户 ${userId} 的购物车...`);
    
    // 获取初始状态 (可能从 SQLite 中恢复)
    const initialCartResult = await system.root.requestFuture(
      pid, 
      { type: CartCommandType.GetCart }, 
      1000
    );
    console.log('初始/恢复的购物车状态:', initialCartResult);
    
    // 添加商品
    console.log('\n添加商品到购物车...');
    const products = [
      { productId: 'p1', name: '笔记本电脑', price: 5999, quantity: 1 },
      { productId: 'p2', name: '无线鼠标', price: 99, quantity: 1 },
      { productId: 'p3', name: '耳机', price: 199, quantity: 2 },
      { productId: 'p4', name: '手机支架', price: 29.9, quantity: 3 }
    ];
    
    for (const product of products) {
      const addResult = await system.root.requestFuture(
        pid, 
        { 
          type: CartCommandType.AddItem, 
          item: product 
        }, 
        1000
      );
      console.log(`添加商品结果:`, (addResult as any).message);
    }
    
    // 获取更新后的购物车
    const updatedCartResult = await system.root.requestFuture(
      pid, 
      { type: CartCommandType.GetCart }, 
      1000
    );
    console.log('\n当前购物车内容:', updatedCartResult);
    
    // 移除一个商品
    console.log('\n移除一个商品...');
    const removeResult = await system.root.requestFuture(
      pid, 
      { 
        type: CartCommandType.RemoveItem, 
        productId: 'p2' 
      }, 
      1000
    );
    console.log('移除商品结果:', (removeResult as any).message);
    
    // 再次获取购物车
    const afterRemoveResult = await system.root.requestFuture(
      pid, 
      { type: CartCommandType.GetCart }, 
      1000
    );
    console.log('\n移除后的购物车内容:', afterRemoveResult);
    
    // 创建快照
    console.log('\n手动创建快照...');
    await system.root.requestFuture(
      pid, 
      { type: CartCommandType.CreateSnapshot }, 
      1000
    );
    
    // 停止 Actor
    console.log('\n停止购物车 Actor...');
    system.root.stop(pid);
    
    // 等待一段时间
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    // 重新创建 Actor
    console.log('\n重新创建购物车 Actor，将从 SQLite 恢复状态...');
    const newPid = system.root.spawn(props);
    
    // 获取恢复的状态
    const recoveredCartResult = await system.root.requestFuture(
      newPid, 
      { type: CartCommandType.GetCart }, 
      1000
    );
    console.log('从 SQLite 恢复后的购物车:', recoveredCartResult);
    
    // 结账
    console.log('\n执行结账...');
    const checkoutResult = await system.root.requestFuture(
      newPid, 
      { type: CartCommandType.Checkout }, 
      1000
    );
    console.log('结账结果:', checkoutResult);
    
    // 尝试在结账后添加商品 (应该被拒绝)
    console.log('\n尝试在结账后添加商品 (应该被拒绝)...');
    const postCheckoutAddResult = await system.root.requestFuture(
      newPid, 
      { 
        type: CartCommandType.AddItem, 
        item: { productId: 'p5', name: '充电器', price: 59, quantity: 1 } 
      }, 
      1000
    );
    console.log('结账后添加商品结果:', postCheckoutAddResult);
    
    // 停止 Actor
    system.root.stop(newPid);
  } catch (error) {
    console.error('执行过程中出错:', error);
  } finally {
    // 关闭 Actor 系统
    await system.terminate();
  }
  
  console.log('\nSQLite 持久化购物车示例完成。您可以重新运行此示例，之前的购物车状态将会被恢复。');
}

/**
 * 运行示例
 */
async function runExample() {
  try {
    await runSQLiteShoppingCartExample();
    console.log('\n示例已完成');
  } catch (error) {
    console.error('示例运行失败:', error);
  }
}

// 执行示例
runExample().catch(console.error); 